

/**	
*	
	Doyle Spiral : 
	introducing scaled rectangle
	aimed to draw elementary circles to understand the theory and the computations to be done
*/

import ij.ImagePlus;
import ij.plugin.PlugIn;
import ij.process.ColorProcessor;
import ij.process.ImageProcessor;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Polygon;
import java.util.ArrayList;
import java.util.Random; 

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;


import pluginUtils.DoyleCircle;


public class doyle8_ extends ImagePlus implements PlugIn {
	
	
	private ImageProcessor primeIP; 
	private int X=2000,Y=2000; // image size
	
	private Random generator=new Random(); // One always needs some randomness
	private ArrayList<DoyleCircle> memoire=new ArrayList<DoyleCircle>();
	private ArrayList<DoyleCircle> traites=new ArrayList<DoyleCircle>();
	private ArrayList<DoyleCircle> traces=new ArrayList<DoyleCircle>();
	// For the scaling of the image
	private double x0=0,x1=1,y0=0,y1=1;
	private double acoef,ccoef,vcoef,wcoef; 
	
	public void setCoefs(){
		acoef=2000/(x1-x0); 
		vcoef=2000/(y1-y0); 
		ccoef=-acoef*x0; 
		wcoef=-vcoef*y0; 
	}
	
	
	public void setBounds(double xl,double xu,double yl,double yu){
		x0=xl; 
		x1=xu;
		y0=yl;
		y1=yu; 
	}
	
	// Adding a control window 
	
	
	
	private int order=0;
	
	private int module=19; 
	
	private double  n=17; //13.0; 
	private double  m=43; //11.0; 
	
	
	private float redColor[]=new float[module]; 
	private float blueColor[]=new float[module];
	private float greenColor[]=new float[module];
	
	private boolean first=true; 
	
	private void drawCircle(DoyleCircle c){
		//if(intersect(c))return; 
		if(c.getRadius()<0.01) return; 
		int intX=(int)(c.getXcenter()*acoef+ccoef);
		int intY=(int)(c.getYcenter()*vcoef+wcoef);
		int intRx=(int)(c.getRadius()*acoef);
		int intRy=(int)(c.getRadius()*vcoef);
		//primeIP.setColor(new Color(redColor[order%module],greenColor[order%module],blueColor[order%module]));
		/*if(first){
			first=false;
			primeIP.drawOval(intX-intR,intY-intR,intR*2,intR*2);
			primeIP.moveTo(intX-85,intY+20); 
			primeIP.drawString("Origin");
		}
		else*/{
			int rank=Math.abs((c.getBpower()%(int)m+c.getApower()%(int)n)%module); 
			
		primeIP.setColor(new Color(redColor[rank],greenColor[rank],blueColor[rank]));
		/*primeIP.setColor(new Color(redColor[generator.nextInt(module)],
									greenColor[generator.nextInt(module)],
									blueColor[generator.nextInt(module)]));*/
		primeIP.drawOval(intX-intRx,intY-intRy,intRx*2,intRy*2);
		if(c.getName()!=null){
		primeIP.moveTo(intX-85,intY+20); 
		primeIP.drawString(c.getName());
		}
		}
		order++;
	}
	
	private void drawLine(double xd,double yd,double xf,double yf){
		int XD=(int)(xd*acoef+ccoef); 
		int YD=(int)(yd*vcoef+wcoef); 
		int XF=(int)(xf*acoef+ccoef); 
		int YF=(int)(yf*vcoef+wcoef);
		primeIP.drawLine(XD,YD,XF,YF); 
	}
	
	

	public void run(String arg) {
		primeIP = new ColorProcessor(X,Y);
	/*	
		 JFrame frame = new JFrame("Converter");
	        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	        frame.setSize(125,800); 

	        //Create and set up the content pane.
	       
	        frame.setContentPane(new JLabel("toto"));

	        //Display the window.
	        frame.pack();
	        frame.setVisible(true);
		
		*/
		
		double r=0.2; 
		double a=1.2416; 
		double b=1.85; 
		System.out.println("--->"+b);
		DoyleCircle.setBounds((int)m, (int)n); 
		
	
		setBounds(-30,30,-30,30); 
		setCoefs(); 
		
		
		System.out.println(Math.pow((1+a)*r,n)+" "+Math.pow((1+b)*r,m)); 
		
		float cseed=0.0f; 
		float step=1.0f/module; 
		for(int i=0;i<module;i++){
			redColor[i]=0.2f+cseed*(1-cseed)*1.6f; 
			blueColor[i]= 0.2f; //0.8f+generator.nextFloat()*0.2f; 
			greenColor[i]=1.0f-cseed*(1-cseed)*1.6f; ; 
			cseed+=step; 
		}
		
		
		// Calcul des angles
		double u[]={1+1/a+b/a,1+1/a+1/b,1+1/b+a/b,1+a+a/b,1+a+b,1+b+b/a};
		double theta[]={Math.acos((u[0]-b/(a*a))/(u[0]+b/(a*a))),
						Math.acos((u[1]-1/(a*b))/(u[1]+1/(a*b))),
						Math.acos((u[2]-a/(b*b))/(u[2]+a/(b*b))),
						Math.acos((u[3]-a*a/b)/(u[3]+a*a/b)),
						Math.acos((u[4]-a*b)/(u[4]+a*b)),
						Math.acos((u[5]-b*b/a)/(u[5]+b*b/a))
		};
	
		
		double radiusCoef[]={b/a,1.0/a,1.0/b,a/b,a,b};
		int modifa[]={-1,-1,0,1,1,0};
		int modifb[]={1,0,-1,-1,0,1};
		
		
		double rotationAngle[]=new double[6];
		rotationAngle[0]=Math.PI-(theta[0]+theta[1]+theta[2]); 
		rotationAngle[1]=Math.PI-(theta[1]+theta[2]+theta[3]); 
		rotationAngle[2]=Math.PI-(theta[2]+theta[3]+theta[4]);
		rotationAngle[3]=Math.PI-(theta[3]+theta[4]+theta[5]); 
		rotationAngle[4]=Math.PI-(theta[4]+theta[5]+theta[0]); 
		rotationAngle[5]=Math.PI-(theta[5]+theta[0]+theta[1]); 
		
		
		
		Polygon background=new Polygon(new int[]{0,0,X,Y},new int[]{0,X,Y,0},4);
		primeIP.setColor(Color.WHITE);
		
		primeIP.fillPolygon(background);
		
		
		primeIP.setFont(new Font(null,Font.ITALIC,60));
		primeIP.setColor(Color.BLACK);
		primeIP.setLineWidth(5); 
		
		//primeIP.moveTo(150,80); 
		//primeIP.drawString("a="+a+"\n"+"b="+b+"\n"+"n="+n+"\n"+"m="+m);
	
		setProcessor("Verifying", primeIP);
		/************************ The drawing begins here *******************************/
		drawLine(0,y0,0,y1); 
		drawLine(x0,0,x1,0);
		DoyleCircle init=new DoyleCircle(0.5,0.5,0,r,0,0); // 0.07
		
		drawCircle(init); 
		memoire.add(init);
		traces.add(init); 
		
		int iter=0; 
		while((!memoire.isEmpty())&&(iter++<300)){
			int index=0; 
			DoyleCircle seed=memoire.get(index); 
			memoire.remove(seed); 
			if(!traites.contains(seed)){
				traites.add(seed); 
				if(!traces.contains(seed)) {drawCircle(seed);traces.add(seed);} 
				
				double theta0=seed.getRotation();
				
				for(int k=0;k<6;k++){
					double rad1=seed.getRadius()*(1+radiusCoef[k]); 
					double nX1=seed.getXcenter()+rad1*Math.cos(theta0);
					double nY1=seed.getYcenter()+rad1*Math.sin(theta0);
					double angle1=seed.getRotation()+rotationAngle[k]; 
					int ca=seed.getApower(); 
					int cb=seed.getBpower(); 
					DoyleCircle c1=new DoyleCircle(nX1,nY1,angle1,seed.getRadius()*radiusCoef[k],
							ca+modifa[k],cb+modifb[k]); 
					if(!memoire.contains(c1)) memoire.add(c1);
					theta0+=theta[k];
					}
			}// if not traite
		}// while memoire ! empty	
		
		show();
	}	
}
	
	
	